/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tewi.controller;

//import tewi.jee.unit.jeeunitest.controller.GlassfishServerController;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.tewi.contexts.ApplicationServerContext;
import pl.tewi.controllers.ServerController;
import pl.tewi.exceptions.AnnotationProcessingException;
import pl.tewi.exceptions.GeneralFrameworkException;
import pl.tewi.exceptions.UnsupportedServerException;
import pl.tewi.types.ApplicationServerType;

/**
 * Fabryka tworząca moduły zarządzające dla różnych serwerów aplikacyjnych. Jest
 * to obiekt tworzący pojedyńczą instancję. TYlko pierwsza inicjalizacja skutkuje
 * później już nie można zmienić typu kontrolera jaki się otrzymuje
 * @author Marcin Kwapisz
 */
public class ServerControllerFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(ServerControllerFactory.class);
    private static Map<String, ServerController> serverControllers = new HashMap<String, ServerController>();

    /**
     * 
     * @param context
     * @return
     * @throws AnnotationProcessingException
     * @throws GeneralFrameworkException
     */
    public static ServerController getServerController(final ApplicationServerContext context) throws AnnotationProcessingException, GeneralFrameworkException {
        //TODO poprawić z uwagi na uruchamianie testów w różnych kontekstach.
        ServerController serverController = serverControllers.get(context.getInstanceName());
        if (serverController != null) {
            return serverController;
        } else {
            try {
                ApplicationServerType type = context.getApplicationServerType();
                ClassLoader classLoader = ServerControllerFactory.class.getClassLoader();
                Class controllerClass = null;
                switch (type) {
                    case GLASSFISH:
                        //załaduj klasę odpowiedzialną z kontrolę nad glassfishem i zwróć obiek kontrolera
                        controllerClass = classLoader.loadClass("pl.tewi.jeeunit.controller.GlassfishServerController");
                        break;
                    case DUMMY:
                        controllerClass = classLoader.loadClass("pl.tewi.jeeunit.controller.DummyServerController");
                        break;
                    default:
                        throw new UnsupportedServerException();
                }
//                serverController = (ServerController) controllerClass.newInstance();
                //wywołaj konstruktor parametrowy. ServerController musi mieć konfigurację serwera
                serverController = (ServerController) controllerClass.getConstructor(ApplicationServerContext.class).newInstance(context);
                serverControllers.put(context.getInstanceName(), serverController);
                return serverController;
            } catch (IllegalArgumentException ex) {
                LOGGER.error("Illegal server controller constructor parameter", ex);
                throw new GeneralFrameworkException("Illegal server controller constructor parameter", ex);
            } catch (InvocationTargetException ex) {
                LOGGER.error("Server controller constructor threw an exception", ex);
                throw new GeneralFrameworkException("Server controller constructor threw an exception", ex);
            } catch (NoSuchMethodException ex) {
                LOGGER.error("Server controller does not have a parameter constructor " + ex.getLocalizedMessage(), ex);
                throw new GeneralFrameworkException("Server controller does not have a parameter constructor " + ex.getLocalizedMessage(), ex);
            } catch (SecurityException ex) {
                LOGGER.error("Security manager error", ex);
                throw new GeneralFrameworkException("Security manager error", ex);
            } catch (InstantiationException ex) {
                LOGGER.error("Server controller class cannot be abstract", ex);
                throw new GeneralFrameworkException("Server controller class cannot be abstract", ex);
            } catch (IllegalAccessException ex) {
                LOGGER.error("Server controller parameter constructor have to be public", ex);
                throw new GeneralFrameworkException("Server controller parameter constructor have to be public", ex);
            } catch (ClassNotFoundException ex) {
                LOGGER.error("Server controller class not found on the classpaath", ex);
                throw new GeneralFrameworkException("Server controller class not found on the classpaath", ex);
            }
        }
    }
}
